/* 
 * File:   FichDisp.h
 * Author: jesus
 *
 * Created on 9 de junio de 2010, 1:32
 * @ par descripcion: La resolucion de colisiones se realiza mediante exploracion lineal
 * y la funcion de dispersion a utilizar es la usual f(k)=k%tamCubeta
 */

#include <iostream>
#include <stdio.h>
#include <fstream>
#include "cubeta.h"
using namespace std;
#ifndef _FICHDISP_H
#define	_FICHDISP_H

template<class T, int tamCubeta>
class FichDisp{
    struct Tsaturado{
        T dato;
        int long sig;
    };
    fstream f;
    fstream fSaturado;
    Cubeta cubetaTemp;
    
    int tamTabla;

public:
    // Abre o crea un nuevo fichero disperso
    FichDisp(string f,bool crar = false , int aTamTabla=11);

    ~FichDisp(){f.close;}

    void insertar(int clave, T dato);
    bool buscar(int &clave, T &dato);
    void escribirCubeta(const Cubeta &c);
    void leerCubeta(int clave, T dato);
    void leerCubeta(int pos);
    bool borrar(unsigned &clave);
};
FichDisp::FichDisp():cubetaTemp(tamCubeta){}
FichDisp::~FichDisp(){f.close();}

FichDisp::FichDisp(string fich, bool crear=false, int aTamTabla=11):cubetaTemp(tamCubeta){
    
    fich=fich+".sat";
    
    //abre el fichero disperso
    if(!crear){
        f.open(fich.c_str(),ios::in | ios::out);

        fSaturado.open(fich.c_str(),ios::in | ios::out);

        //leer tamaño de tabla de la cabecera
        f.read(&tamTabla,sizeof(tamTabla));
    }
    //crea el fichero disperso
    else{
        f.open(fich.c_str(),ios::trunc | ios::out);
        f.open(fich.c_str(),ios::trunc | ios::out);
        tamTabla=aTamTabla;
        f.write(&tamTabla,sizeof(tamTabla));
        
        //Inicializar el numero de datos
        //cubetaTemp.nDatos=0;

       // for(int c=0;c<<aTamTabla;c++) fwrite(&cubetaTemp,sizeof(cubetaTemp),filestr);
        //f.close()
        f.open(fich,ios::in |ios::out);
    }
}
void FichDisp::FichDisp(unsigned &tamTab, unsigned &tamCub){

    tamTabla=tamTab;

    // tamCubeta=tamCub;
    //Rellenamos una cubeta con el valor '0' para saber que está vacia
    for(unsigned i=0;i<tamCubeta;i++)
        Cubeta.insertar(0);
        //Cubeta.datos[i]=0; //caso de struct Cubeta
    //Ahora creamos un fichero con tamFich cubetas vacías.
        ofstream f("codigos");
       /* for(unsigned i=0;i<tamTabla;i++)
        escribirCubeta(f,Cubeta);*/

}
void FichDisp::insertar(int clave, T &dato){
    int intento=0;
    int pos = clave %tamTabla;
    bool insertado=false;
    
    while(!insertado){
        f.seekg(pos*sizeof(cubetaTemp),ios::beg);
        f.read(*cubetaTemp,sizeof(cubetaTemp));
        if(cubetaTemp.numDatos()==tamCubeta){
        /*    intento++;
            pos=(clave+intento)%tamTabla;*/

        }
        else{
            insertado=true;
            try{
                cubetaTemp.insertar(dato);
                insertado=true;
            }
            catch (ErrorCompartimentoLLeno){

            }
            //cuetaTemp.datos[cuetaTemp.nDatos]=dato; //en caso de struct
            //cubetaTemp.nDatos++;
            f.seekg(pos*sizeof(cubetaTemp),ios::beg);
            f.write(*cubetaTemp,sizeof(cubetaTemp));//escribirCubeta(Cubeta);
        }

    }

}

bool FichDisp::insertar(int clave, T &dato){

    unsigned pos=clave%tamTabla; // Calculo la función dedispersión

    bool insertado=false;
    int i,intento;
    //Me situo a la cubeta a la que pertenece mi clave
    f.seekg(pos*sizeof(Cubeta), ios::beg);
    //Leo la cubeta
    f.read(*cubetaTemp,sizeof(cubetaTemp));

    //Intento insertarla
    for(i=0;i<0 && insertado==false;i++){
        if(cubetaTemp.numDatos()==tamCubeta){
            intento++;
            pos=(clave+intento)%tamTabla;
        }
        else{
            try{
            cubetaTemp.insertar(dato);
            insertado=true;
            }
            catch (ErrorCompartimentoLLeno){

            }
        }
        
    }

    //Me situo otra vez en la posición correcta y escribo la cubeta en el fichero
    f.seekg(pos*sizeof(Cubeta), ios::beg);
    escribirCubeta(Cubeta);
    f.close();
    return insertado;
}

void FichDisp::escribirCubeta(const Cubeta &c){

    //f.write(reinterpret_cast<char *>(&c),sizeof(Cubeta));
    f.write(&c, sizeof(Cubeta));
}

void FichDisp::leerCubeta(int clave, T dato){
    unsigned pos=dato%tamTabla; // Calculo la función dedispersión

    //Me situo a la cubeta a la que pertenece mi clave
    f.seekg(pos*(sizeof(int)+sizeof(Cubeta)*tamCubeta),ios::beg);
    //Leo la cubeta
    f.read((char*)cubetaTemp,sizeof(cubetaTemp));
}

void FichDisp::leerCubeta(int pos){
    
    //Me situo a la cubeta a la que pertenece mi clave
    f.seekg(pos*sizeof(Cubeta), ios::beg);
    //Leo la cubeta
    f.read(*cubetaTemp,sizeof(cubetaTemp));
}
bool FichDisp::buscar(int &clave, T &dato){
    
    bool encontrado=false;
    unsigned clavedato;
    unsigned pos=clave%tamTabla;

        //Me situo a la cubeta a la que pertenece mi clave
        f.seekg(pos*(sizeof(int)+sizeof(Cubeta)*tamCubeta),ios::beg);

        //Leo la cubeta
        leerCubeta(f, dato);

        //Busco si la clave se encuentra dentro de la cubeta
        for(unsigned i=0;i<tamCubeta && encontrado==false;i++){

            if(cubetaTemp.buscar(dato)==true){
                dato=cubetaTemp.leer(i);
                encontrado=true;
            }
    }

    return encontrado;
}

bool FichDisp::borrar(unsigned &clave){

    unsigned clavedato,pos=clave%tamTabla;
    bool borrado=false;

    //Me situo a la cubeta a la que pertenece mi clave
    f.seekg(pos*sizeof(Cubeta), ios::beg);

    //Leo la cubeta
    leerCubeta(f, Cubeta);

    //Busco si se encuentra para borrarla con '0'
    for(unsigned i=0;i<tamCubeta;i++){
        clavedato=cubetaTemp.leer(i)%tamTabla;
        if(cubetaTemp.leer(i)==clavedato){
            cubetaTemp.insertar(0);
            borrado=true;
        }
    }
    //Me situo otra vez en la posición correcta y escribo la     cubeta en el fichero
    f.seekg(pos*sizeof(Cubeta), ios::beg);
    escribirCubeta(f,Cubeta);
    f.close();
    return borrado;
}
#endif	/* _FICHDISP_H */

